
const char *pMagicString = "BENZ C\r\n\r\n";

typedef struct _MCU_UPDATE_INFO{
	U8 HexBuff[64];
	U8 HexLineByteCountNow;
	
	U16 HexAddH16;
	U16 HexAddL16;
	
	U32 HexAddFlashAddStart;
	U32 HexAddFlashAddEnd;

	BOOL MCUCheckHexAddress;

	U32 calcMCUHexCRC;
	U8 magicStringBuffWindow[8];
	BOOL haveFindMagicString;
}MCU_UPDATE_INFO;

MCU_UPDATE_INFO mcuUpdateInfo;

U8 Hex4BitCharTarnsValue(U8 cHex)
{
	if (cHex >= '0' && cHex <= '9')
	{
		return cHex-'0';
	}
	else if (cHex >= 'A' && cHex <= 'F')
	{
		return cHex-'A'+10;
	}
	else if (cHex >= 'a' && cHex <= 'f')
	{
		return cHex-'a'+10;
	}
	else
	{
		return 0;
	}
}

BOOL HexCalcCRC(U8 *pData)
{
	U8 i;
	U8 len = pData[0];
	U8 crc = 0;
	for (i = 0;i < 1+2+1+len;i++)
	{
		crc += pData[i];
	}
	crc = 0x100-crc;
	
	if (crc == pData[1+2+1+len])
	{
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}

void findMagicString(U8 data)
{
	memmove(&mcuUpdateInfo.magicStringBuffWindow[0],
		&mcuUpdateInfo.magicStringBuffWindow[1],
		sizeof(mcuUpdateInfo.magicStringBuffWindow)-1);

	mcuUpdateInfo.magicStringBuffWindow[sizeof(mcuUpdateInfo.magicStringBuffWindow)-1] = data;

	if (0 == memcmp(pMagicString,mcuUpdateInfo.magicStringBuffWindow,sizeof(mcuUpdateInfo.magicStringBuffWindow)))
	{
		mcuUpdateInfo.haveFindMagicString = TRUE;
	}
}

void HexDataWrite(U8 *pData,U32 len)
{
	U32 writeAdd = (mcuUpdateInfo.HexAddH16<<16) + mcuUpdateInfo.HexAddL16;
	U32 writeData;
	U32 writeOffset;

	writeOffset = 0;
	while (len)
	{
		findMagicString(*pData);
		
		writeData >>= 8;
		writeData |= (*pData)<<24;
		writeOffset++;
		if (4 == writeOffset)
		{
			writeOffset = 0;
			if (writeAdd >= mcuUpdateInfo.HexAddFlashAddStart
				&& writeAdd < mcuUpdateInfo.HexAddFlashAddEnd)
			{
			}
			else
			{
				mcuUpdateInfo.HexAddFlashAddStart = writeAdd&(~(FLASH_SECTOR_SIZE-1));
				mcuUpdateInfo.HexAddFlashAddEnd = mcuUpdateInfo.HexAddFlashAddStart+FLASH_SECTOR_SIZE;
				flashErasePage(mcuUpdateInfo.HexAddFlashAddStart);

				if (0xFFFFFFFF == *(U32 *)SYSTEM_CFG_FILE_UPDATE)
				{
					flashWriteWord(SYSTEM_CFG_FILE_UPDATE,0);
				}
			}
			flashWriteWord(writeAdd,writeData);
			writeAdd += 4;
		}
		pData++;
		len--;
	}
}

void HexDataProc(U8 *pData)
{
	switch (pData[3])
	{
		case 0x05:
			mcuUpdateInfo.HexAddH16 = (pData[4]<<8) + pData[5];
			mcuUpdateInfo.HexAddL16 = (pData[6]<<8) + pData[7];
			break;

		case 0x04:
			mcuUpdateInfo.HexAddH16 = (pData[4]<<8) + pData[5];
			break;

		case 0x00:
			mcuUpdateInfo.HexAddL16 = (pData[1]<<8) + pData[2];
			if (!mcuUpdateInfo.MCUCheckHexAddress)
			{
				if (SYSTEM_ADD == (mcuUpdateInfo.HexAddH16<<16)+mcuUpdateInfo.HexAddL16)
				{					
					mcuUpdateInfo.MCUCheckHexAddress = TRUE;
				}
				else
				{
					conNaviBoardReportMCUStatus(4);
					naviBoardInfo.MCUUpdateIng = FALSE;
				}
			}

			if (mcuUpdateInfo.MCUCheckHexAddress)
			{
				HexDataWrite(&pData[4],pData[0]);
			}
			break;

		case 0x01://Finish
			if (mcuUpdateInfo.calcMCUHexCRC != naviBoardInfo.MCUHexCRC)
			{
				conNaviBoardReportMCUStatus(2);
				printf("bootloader update fail on crc error! Calc:%x Rec:%x\r\n",mcuUpdateInfo.calcMCUHexCRC,naviBoardInfo.MCUHexCRC);
			}
			else
			{
				flashWriteWord(SYSTEM_CFG_FILE_SIZE,naviBoardInfo.MCUHexSize);
				flashWriteWord(SYSTEM_CFG_FILE_CRC,naviBoardInfo.MCUHexCRC);

				if (!mcuUpdateInfo.haveFindMagicString)
				{
					conNaviBoardReportMCUStatus(3);
					printf("bootloader update fail on have not find magic string!\r\n");
				}
				else
				{
					conNaviBoardReportMCUStatus(0xFF);
					flashWriteWord(SYSTEM_VALID_ADD,SYSTEM_VALID_PARA);
					printf("bootloader update finish!\r\n");
				
					DelayTimer(T_1MS*500);
					
					tryGotoSystem(FALSE);
				}
			}
			
			naviBoardInfo.MCUUpdateIng = FALSE;
			break;
	}
}

void MCUUpdateProc(U8 *pData,U32 length)
{
	while (length)
	{
		if (':' == *pData || 0x0D == *pData || 0x0A == *pData)
		{
			mcuUpdateInfo.HexLineByteCountNow = 0;
		}
		else
		{
			if (mcuUpdateInfo.HexLineByteCountNow >= 128)
			{
			}
			else
			{
				if (mcuUpdateInfo.HexLineByteCountNow % 2 == 0)//H4Bit
				{
					mcuUpdateInfo.HexBuff[mcuUpdateInfo.HexLineByteCountNow/2] &= 0x0F;
					mcuUpdateInfo.HexBuff[mcuUpdateInfo.HexLineByteCountNow/2] |= Hex4BitCharTarnsValue(*pData)<<4;
				}
				else
				{
					mcuUpdateInfo.HexBuff[mcuUpdateInfo.HexLineByteCountNow/2] &= 0xF0;
					mcuUpdateInfo.HexBuff[mcuUpdateInfo.HexLineByteCountNow/2] |= Hex4BitCharTarnsValue(*pData);
				}
				
				mcuUpdateInfo.HexLineByteCountNow++;
			}
			
			if (mcuUpdateInfo.HexLineByteCountNow >= 2)
			{
				if (0 == mcuUpdateInfo.HexLineByteCountNow%2)
				{
					if (mcuUpdateInfo.HexLineByteCountNow/2 == 1+2+1+mcuUpdateInfo.HexBuff[0]+1)
					{
						if (HexCalcCRC(mcuUpdateInfo.HexBuff))
						{
							HexDataProc(mcuUpdateInfo.HexBuff);
							mcuUpdateInfo.HexBuff[0] = 0;
						}
					}
				}
			}
		}
		pData++;
		length--;
	}
}

void MCUUpdateInit(void)
{
	memset(&mcuUpdateInfo,0,sizeof(MCU_UPDATE_INFO));
}

